#ifndef FUNCFILLER_H
#define FUNCFILLER_H

#include "Core/Tensor.h"
#include "RectDomain.H"
#include "Circle.H"


template <int Dim>
class FuncFiller
{
public:
  using iVec = Vec<int, Dim>;
  using rVec = Vec<Real, Dim>;
  FuncFiller(const RectDomain<Dim> &_rd) : rd(_rd) {}

public:
  template <class TFunc>
  void fillDomainVal(Tensor<Real, Dim> &aData, const TFunc &expr) const;

  template <class TFunc>
  void fillRectBdrVal(Tensor<Real, Dim - 1> &aData, int D, int side, const TFunc &expr) const;

  template <class TFunc>
  void fillRectBdrNormalGrad(Tensor<Real, Dim - 1> &aData, int D, int side, const TFunc &expr) const;


protected:
  RectDomain<Dim> rd;
};

//============================================================

template <>
template <class TFunc>
inline void FuncFiller<2>::fillDomainVal(Tensor<Real, 2> &aData, const TFunc &expr) const
{
  rVec dx = rd.spacing();
  Box<2> bx = rd;
  assert(aData.box().contain(bx));
  loop_box_2(bx, i, j)
  {
    iVec idx{i, j};
    aData(i, j) = expr(dx * idx);
  }
}

template <>
template <class TFunc>
inline void FuncFiller<2>::fillRectBdrVal(Tensor<Real, 1> &aData,
                                          int D,
                                          int side,
                                          const TFunc &expr) const
{
  RectDomain<2> srd = rd;
  rVec dx = srd.spacing();
  auto sideBox = reduce(srd, D);
  assert(aData.box().contain(sideBox));
  int a = (side == -1) ? (srd.lo()[D]) : (srd.hi()[D]);
  loop_box_1(sideBox, j)
  {
    iVec idx;
    idx[D] = a;
    idx[1 - D] = j;
    aData(j) = expr(dx * idx);
  }
}

template <>
template <class TFunc>
inline
void FuncFiller<2>::fillRectBdrNormalGrad(Tensor<Real, 1> &aData,
                                     int D,
                                     int side,
                                     const TFunc &expr) const
{
  fillRectBdrVal(aData, D, side, [&](const auto &x) { return expr(x)[D] * side; });
}

#endif // FUNCFILLER_H
